import React, { CSSProperties, useEffect, useState } from "react";
import { PickerView, PickerViewColumn, View } from "@tarojs/components";
import { DatePickerProps } from "../../../types/components/date-picker";

/**
 * DatePicker 选择时间Picker
 */
const DatePicker: React.FC<DatePickerProps> = ({
  mode = "date",
  minDate = new Date("1900/01/01"),
  maxDate = new Date("2100/01/01"),
  defaultValue = new Date(),
  onChange,
  columnStyle,
  textStyle,
  activeTextStyle,
  style
}) => {
  // 设置picker默认植
  const [pickerValue, setPickerValue] = useState<number[]>([]);
  // 1 2 3列数据
  const [pickerData, setPickerData] = useState<string[][]>([]);

  // 计算出数据源
  useEffect(() => {
    let pickerData: string[][] = []; // 源数据
    // 1. 年 最小、最大
    let years: string[] = [];
    for (
      let year = minDate.getFullYear();
      year <= maxDate.getFullYear();
      year++
    ) {
      years.push(year + "年");
    }
    pickerData.push(years);

    if (mode === "date" || mode === "date-year-month") {
      // 2. 月
      const months: string[] = [
        "1月",
        "2月",
        "3月",
        "4月",
        "5月",
        "6月",
        "7月",
        "8月",
        "9月",
        "10月",
        "11月",
        "12月"
      ];
      pickerData.push(months);
    }

    if (mode === "date") {
      // 3. 日
      const days: string[] = [
        "1日",
        "2日",
        "3日",
        "4日",
        "5日",
        "6日",
        "7日",
        "8日",
        "9日",
        "10日",
        "11日",
        "12日",
        "13日",
        "14日",
        "15日",
        "16日",
        "17日",
        "18日",
        "19日",
        "20日",
        "21日",
        "22日",
        "23日",
        "24日",
        "25日",
        "26日",
        "27日",
        "28日",
        "29日",
        "30日",
        "31日"
      ];
      pickerData.push(days);
    }
    // 拿到有效日期
    const validDate = getValidDate(
      `${defaultValue.getFullYear()}/${defaultValue.getMonth() +
        1}/${defaultValue.getDate()}`
    );
    // 计算数据源、日期所对应的下标索引
    const pickerValue = getPickerValue(pickerData, validDate);

    setPickerData(pickerData);
    setPickerValue(pickerValue);
    // 主动回调onChange
    onChange && onChange(validDate);
  }, []);

  // 输入:日期
  // 输出：范围内的有效日期 min <= date <= max && 日期合法[月->日] // 闰年/是否有31
  const getValidDate = (date: string /** 'yyyy/mm/dd' */) => {
    let validDate = new Date(date);
    // 无效日期
    if (!(validDate instanceof Date)) {
      return minDate;
    }
    if (mode === "date") {
      validDate = _getValidDate(date);
    }
    // 有效日期范围内
    if (validDate.getTime() < minDate.getTime()) {
      // 年
      if (validDate.getFullYear() < minDate.getFullYear()) {
        validDate.setFullYear(minDate.getFullYear());
      }
      // 月
      if (
        validDate.getTime() < minDate.getTime() &&
        validDate.getMonth() < minDate.getMonth()
      ) {
        validDate.setMonth(minDate.getMonth());
      }
      // 日
      if (validDate.getTime() < minDate.getTime()) {
        validDate = new Date(minDate);
      }
    }
    if (validDate.getTime() > maxDate.getTime()) {
      // 年
      if (validDate.getFullYear() > maxDate.getFullYear()) {
        validDate.setFullYear(maxDate.getFullYear());
      }
      // 月
      if (
        validDate.getTime() > maxDate.getTime() &&
        validDate.getMonth() > maxDate.getMonth()
      ) {
        validDate.setMonth(maxDate.getMonth());
      }
      // 日
      if (validDate.getTime() > maxDate.getTime()) {
        validDate = new Date(maxDate);
      }
    }
    return validDate;
  };

  // 根据年月日数据源、下标索引，计算出对组合后的日期
  const getChangeDate = (data: string[][], indexs: number[]) => {
    let date: string[] = [];
    for (let index = 0; index < data.length; index++) {
      const elements = data[index]; // 列数组
      const row = indexs[index]; // 列对应的行索引
      if (elements && elements[row]) {
        const s = elements[row];
        date.push(
          s
            .replace(/年/g, "")
            .replace(/月/g, "")
            .replace(/日/g, "")
        );
      }
    }
    return date.join("/");
  };

  // 根据年月日数据源，计算出对应所在indexs
  const getPickerValue = (data: string[][], date: Date) => {
    let indexs: number[] = [];
    let dateS: string[] = [
      `${date.getFullYear()}年`,
      `${date.getMonth() + 1}月`,
      `${date.getDate()}日`
    ];
    for (let index = 0; index < data.length; index++) {
      const elements = data[index]; // 列数组
      const ds = dateS[index];
      const i = elements.findIndex(e => e === ds);
      indexs.push(i > -1 ? i : 0);
    }
    return indexs;
  };

  // 获取合法的日期: 如果转换前后的年月日相等则为合法 28/29/30/31
  const _getValidDate = (date: string /** 'yyyy/mm/dd' */) => {
    let validDate = new Date(date);
    const dateS = `${validDate.getFullYear()}/${validDate.getMonth() +
      1}/${validDate.getDate()}`;
    if (date !== dateS) {
      // 日期校正
      const dates = date.split("/");
      const day = getValidDay(Number(dates[0]), Number(dates[1]));
      validDate = new Date(`${dates[0]}/${dates[1]}/${day}`);
    }
    return validDate;
  };

  function getValidDay(year: number, month: number) {
    let dayT: number = 1;
    switch (month) {
      case 1:
      case 3:
      case 5:
      case 7:
      case 8:
      case 10:
      case 12:
        dayT = 31;
        break;
      case 4:
      case 6:
      case 9:
      case 11:
        dayT = 30;
        break;
      case 2:
        dayT = year % 4 === 0 ? 29 : 28;
        break;
    }
    return dayT;
  }

  const onDateChange = e => {
    // 1. 拿到原始数组索引
    let indexs: number[] = e.detail.value;
    // 2. 根据索引拿到原始的年月日字符串
    let date = getChangeDate(pickerData, indexs);
    // 3. 拿到有效日期
    const validDate = getValidDate(date);
    // 4. 计算数据源、日期所对应的下标索引
    const pickerValueT = getPickerValue(pickerData, validDate);
    // 5. 更正索引值
    setPickerValue(pickerValueT);

    onChange && onChange(validDate);
  };

  const getStyle = (index, col): CSSProperties => {
    const active = index === pickerValue[col];
    if (active && activeTextStyle) {
      return activeTextStyle;
    }
    return {
      overflow: "hidden",
      whiteSpace: "nowrap",
      textOverflow: "ellipsis",
      height: 34 + "px",
      lineHeight: 34 + "px",
      fontWeight: active ? 600 : 400,
      color: active ? "#FF7242" : "#000000",
      ...textStyle
    };
  };

  return (
    <PickerView
      indicatorStyle="height: 34px;"
      style={{
        height: 430 + 'rpx',
        backgroundColor: "#ffffff",
        ...style
      }}
      value={pickerValue}
      onChange={onDateChange}
    >
      {pickerData && pickerData.length > 0
        ? pickerData.map((d, index) => {
            return (
              <PickerViewColumn
                key={index}
                style={{
                  textAlign: "center",
                  // height: "250rpx",
                  ...columnStyle
                }}
              >
                {d.map((item, i) => {
                  return (
                    <View style={getStyle(i, index)} key={i}>
                      {item}
                    </View>
                  );
                })}
              </PickerViewColumn>
            );
          })
        : null}
    </PickerView>
  );
};
export default DatePicker;
